package org.fast.develop.logicflow.builder;

import org.fast.develop.logicflow.core.meta.shape.LogicFlowDefinition;
import org.fast.develop.logicflow.core.meta.base.Element;
import org.fast.develop.logicflow.core.meta.base.Ref;
import org.fast.develop.logicflow.core.meta.base.line.Incoming;
import org.fast.develop.logicflow.core.meta.base.line.Outgoing;
import org.fast.develop.logicflow.core.meta.base.Resource;
import org.fast.develop.logicflow.core.meta.shape.control.IfElseControl;
import org.fast.develop.logicflow.core.meta.shape.line.SequenceFlow;
import org.fast.develop.logicflow.core.LogicFlowConfiguration;

import java.lang.reflect.InvocationTargetException;
import java.util.UUID;

/**
 * @author 莫寅
 * @createTime 2022-11-25 19:24
 * @desc：
 */
public class LogicFlowBuilderFactory {

    private LogicFlowConfiguration logicFlowConfiguration;

    public LogicFlowBuilderFactory(LogicFlowConfiguration logicFlowConfiguration) {
        this.logicFlowConfiguration = logicFlowConfiguration;
    }



    public <T extends AbstractLogicFlowBuilder>T createBuilder(String id, Class<T> abstractLogicFlowBuilderClass, AbstractLogicFlowBuilder prevAbstractLogicFlowBuilder, LogicFlowDefinition logicFlowDefinition){
        //初始化当前构建器
        T abstractLogicFlowBuilder = startCreateBuilder(id, abstractLogicFlowBuilderClass, prevAbstractLogicFlowBuilder, logicFlowDefinition);

        //控制器逻辑处理
        parseControl(abstractLogicFlowBuilder, prevAbstractLogicFlowBuilder);

        logicFlowConfiguration.getLogicFlowBuilderFactory().addDefinitionsElement(abstractLogicFlowBuilder);
        return abstractLogicFlowBuilder;
    }


    private void parseControl(AbstractLogicFlowBuilder currentAbstractLogicFlowBuilder, AbstractLogicFlowBuilder prevAbstractLogicFlowBuilder){
        //判断上一个构建器是否网关，是就设置给当前构建器
        if(prevAbstractLogicFlowBuilder instanceof IfElseControlBuilder){
            currentAbstractLogicFlowBuilder.setCurrentGatewayAbstractLogicFlowBuilder((IfElseControlBuilder) prevAbstractLogicFlowBuilder);
        }else{
            currentAbstractLogicFlowBuilder.setCurrentGatewayAbstractLogicFlowBuilder(prevAbstractLogicFlowBuilder.getCurrentGatewayAbstractLogicFlowBuilder());
        }
    }


    public <T extends AbstractLogicFlowBuilder>T create(Class<T> abstractLogicFlowBuilderClass, LogicFlowDefinition logicFlowDefinition){

        try {
            return abstractLogicFlowBuilderClass
                    .getConstructor(LogicFlowDefinition.class, LogicFlowConfiguration.class)
                    .newInstance(logicFlowDefinition, logicFlowConfiguration);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return null;
    }

    public <T extends AbstractLogicFlowBuilder>T startCreateBuilder(String id, Class<T> abstractLogicFlowBuilderClass, AbstractLogicFlowBuilder prevAbstractLogicFlowBuilder, LogicFlowDefinition logicFlowDefinition){
        if(id == null){
            id = UUID.randomUUID().toString();
        }
        T abstractLogicFlowBuilder = createLogicFlow(abstractLogicFlowBuilderClass, logicFlowDefinition);
        abstractLogicFlowBuilder.id(id);


        prevAbstractLogicFlowBuilder.addOutgoing(abstractLogicFlowBuilder);

        abstractLogicFlowBuilder.setPrevAbstractLogicFlowBuilder(prevAbstractLogicFlowBuilder);

        return abstractLogicFlowBuilder;
    }

    /**
     * 获取或创建连接线
     * @param abstractLogicFlowBuilder
     * @return
     */
    private SequenceFlow getOrCreateSequenceFlow(AbstractLogicFlowBuilder abstractLogicFlowBuilder){
        AbstractLogicFlowBuilder prevAbstractLogicFlowBuilder = abstractLogicFlowBuilder.getPrevAbstractLogicFlowBuilder();
        Element preElement = prevAbstractLogicFlowBuilder.getElement();

        //当前节点连接线
        SequenceFlow currentSequenceFlow = null;

        if(abstractLogicFlowBuilder.getCurrentGatewayAbstractLogicFlowBuilder()!= null){
            IfElseControlBuilder ifElseControlBuilder = abstractLogicFlowBuilder.getCurrentGatewayAbstractLogicFlowBuilder();
            SequenceFlow sequenceFlow = ifElseControlBuilder.nextSequenceFlow();

            if(sequenceFlow != null){
                //给ifelse控制网关加上输入线
                Ref ref = new Ref();
                ref.setResourceId(sequenceFlow.getResourceId());
                ifElseControlBuilder.getElement().getOutgoing().add(ref);
            }



            if(sequenceFlow != null){
                currentSequenceFlow = sequenceFlow;
            }
        }

        if(currentSequenceFlow == null && !(preElement instanceof LogicFlowDefinition)){
            currentSequenceFlow = createSequenceFlow();
            currentSequenceFlow.setName("sequenceFlow_" + preElement.getName());
        }
        return currentSequenceFlow;
    }

    protected void addDefinitionsElement(AbstractLogicFlowBuilder abstractLogicFlowBuilder){
        Resource resource = abstractLogicFlowBuilder.getElement();

        abstractLogicFlowBuilder.addIncoming(abstractLogicFlowBuilder.getPrevAbstractLogicFlowBuilder());

        AbstractLogicFlowBuilder prevAbstractLogicFlowBuilder = abstractLogicFlowBuilder.getPrevAbstractLogicFlowBuilder();
        Element preElement = prevAbstractLogicFlowBuilder.getElement();
        Element currentElement = abstractLogicFlowBuilder.getElement();

        //当前节点连接线
        SequenceFlow currentSequenceFlow = getOrCreateSequenceFlow(abstractLogicFlowBuilder);


        if(preElement instanceof Outgoing && !(preElement instanceof IfElseControl)){
            Outgoing outgoing = (Outgoing)preElement;
            Ref ref = new Ref();
            ref.setResourceId(currentSequenceFlow.getResourceId());
            outgoing.getOutgoing().add(ref);
        }


        if(currentSequenceFlow != null){
            //设置当前连接线的来源
            Ref sourceRef = new Ref();
            sourceRef.setResourceId(preElement.getResourceId());
            currentSequenceFlow.setSourceRef(sourceRef);
            //设置当前连接线的目标
            Ref targetRef = new Ref();
            targetRef.setResourceId(currentElement.getResourceId());
            currentSequenceFlow.setTargetRef(targetRef);
            abstractLogicFlowBuilder.getLogicFlowDefinition().getDefinitions().getList().add(currentSequenceFlow);

            if(currentElement instanceof Incoming){
                Incoming incoming = (Incoming)currentElement;
                Ref ref = new Ref();
                ref.setResourceId(currentSequenceFlow.getResourceId());
                incoming.getIncoming().add(ref);
            }
        }

        abstractLogicFlowBuilder.getLogicFlowDefinition().getDefinitions().getList().add(resource);
    }


    protected <T extends AbstractLogicFlowBuilder>T createLogicFlow(Class<T> abstractLogicFlowBuilderClass, LogicFlowDefinition logicFlowDefinition){
        T abstractLogicFlowBuilder = logicFlowConfiguration.getLogicFlowBuilderFactory().create(abstractLogicFlowBuilderClass, logicFlowDefinition);
        Resource resource = logicFlowConfiguration.getElementFactory().create(abstractLogicFlowBuilder.getElementClass());
        abstractLogicFlowBuilder.setElement(resource);
        return abstractLogicFlowBuilder;
    }


    public SequenceFlow createSequenceFlow(){
        SequenceFlow sequenceFlow = logicFlowConfiguration.getElementFactory().create(SequenceFlow.class);
        sequenceFlow.setResourceId(UUID.randomUUID().toString());
        return sequenceFlow;
    }


    public Resource createResource(Class<Resource> resourceClass){
        Resource resource = logicFlowConfiguration.getElementFactory().create(resourceClass);
        resource.setResourceId(UUID.randomUUID().toString());
        return resource;
    }
}
